js 事件流
js 事件流是指事件在 dom 中流转的顺序(或者传播路径),事件流转分为三个过程,捕获阶段 - 目标阶段 - 冒泡阶段。下面我们通过实践探索下事件流机制。
实践
首先用 html 和 css 实现如下效果
接着我们通过 js 代码来控制事件回调执行的时机
- 回调在冒泡阶段执行
1 | function log(msg) { |
我们分别点击wrapper、outer、inner,查看打印结果
点击对象 | 打印结果 |
---|---|
wrapper | wrapper |
outer | outer、wrapper |
inner | inner、outer、wrapper |
从打印结果我们可以得出如下结论:
当我们点击某个节点时,首先打印该节点的内容,然后,从该节点开始向上冒泡,若父级监听了相同的事件, 那么父级对应的事件回调也会执行,直到 window。
- 回调在捕获阶段执行
接着我们把上面 js 代码 addEventListener 的第三个参数改为 true,让回调在捕获阶段执行,
1 | function log(msg) { |
然后再次分别点击wrapper、outer、inner,查看打印结果
点击对象 | 打印结果 |
---|---|
wrapper | wrapper |
outer | wrapper、outer |
inner | wrapper、outer、inner |
从这次的打印结果,我们可以得出结论:
当某个节点被点击时,事件流从顶级 window 依次向下传播,若传播到的节点也监听了相同的事件,那么该事件的回调也会执行,直到该点击节点。
- 混合
下面我们看下更复杂的情况
1 | function log(msg) { |
依次点击wrapper、outer、inner, 看下打印结果
点击对象 | 打印结果 |
---|---|
wrapper | wrapper one、wrapper two |
outer | wrapper one、outer、wrapper two |
inner | wrapper one、inner、outer、wrapper two |
总结:
事件回调的执行顺序是按照事件流来的传播顺序执行的,首先是捕获阶段,若从window 到 当前点击节点的有捕获阶段的监听函数,则按照从顶级 window 到当前点击节点的传播顺序执行回调,接着到达目标阶段,即执行当前点击节点的回调,最后是冒泡阶段,若从当前节点到顶级 window 有冒泡阶段的监听函数,则按照这个传播顺序执行回调。
注: 事件的监听节点可以看做是目标阶段,若是一个节点既在捕获阶段又在冒泡阶段监听了相同的事件,那么这个节点两个事件回调的执行顺序按照事件的添加的顺序执行(不区分捕获阶段和冒泡阶段,同属于目标阶段)。